package com.xinyue.gateway.server;

import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import com.xinyue.gateway.config.GateServerConfig;
import com.xinyue.gateway.server.handler.ChannelConnectConfirmHandler;
import com.xinyue.gateway.server.handler.GameHeartbeatHandler;
import com.xinyue.gateway.server.handler.GameIdleStateHandler;
import com.xinyue.gateway.server.handler.GameMessageDecodeHandler;
import com.xinyue.gateway.server.handler.GameMessageEncodeHandler;
import com.xinyue.gateway.server.handler.InnerPackageEncodeHandler;
import com.xinyue.gateway.service.GateChannelGroupService;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;

@Service
public class GameGatewayBootServer {

    private NioEventLoopGroup bossGroup = null;
    private EventLoopGroup workerGroup = null;
    private Logger logger = LoggerFactory.getLogger(GameGatewayBootServer.class);
    @Autowired
    private GateServerConfig serverConfig;
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private GateChannelGroupService channelService;

    public void init() {
        bossGroup = new NioEventLoopGroup(serverConfig.getBossThreads());
        // 业务逻辑线程组
        workerGroup = new NioEventLoopGroup(serverConfig.getWorkThreads());
        // 初始化channel管理容器
        channelService.init(workerGroup);
    }

    public void startServer() {
        int port = this.serverConfig.getPort();

        try {
            ServerBootstrap b = new ServerBootstrap();
            // 这里遇到一个小问题，如果把childHandler的加入放在option的前面，option将会不生效。我用java socket连接，一直没有消息返回。
            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true).childOption(ChannelOption.TCP_NODELAY, true).childHandler(createChannelInitializer());
            logger.info("开始启动服务，端口:{}", serverConfig.getPort());
            ChannelFuture f = b.bind(port).sync();
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    private ChannelInitializer<Channel> createChannelInitializer() {
        ChannelInitializer<Channel> channelInitializer = new ChannelInitializer<Channel>() {

            @Override
            protected void initChannel(Channel ch) throws Exception {
                ChannelPipeline p = ch.pipeline();
                ChannelConnectConfirmHandler channelConnectConfirmHandler = applicationContext.getBean(ChannelConnectConfirmHandler.class);
                GameMessageDecodeHandler gameMessageDecode = applicationContext.getBean(GameMessageDecodeHandler.class);
                GameMessageEncodeHandler gameMessageEncode = applicationContext.getBean(GameMessageEncodeHandler.class);
                InnerPackageEncodeHandler dispatchMessageHandler = applicationContext.getBean(InnerPackageEncodeHandler.class);
                GameIdleStateHandler gameIdleStateHandler = applicationContext.getBean(GameIdleStateHandler.class);
                GameHeartbeatHandler gameHeartbeatHandler = applicationContext.getBean(GameHeartbeatHandler.class);
                // 添加接收消息包的handler
                p.addLast(new LengthFieldBasedFrameDecoder(1024 * 10, 0, 2, -2, 0));

                // 解码消息包
                p.addLast(gameMessageDecode);
                // 编码消息包
                p.addLast(gameMessageEncode);
                p.addLast(gameIdleStateHandler);
                p.addLast(gameHeartbeatHandler);
                // 连接认证
                p.addLast(channelConnectConfirmHandler);
                // 消息转化
                p.addLast(dispatchMessageHandler);
            }
        };
        return channelInitializer;
    }

    public void stop() {
        int quietPeriod = 5;
        int timeout = 30;
        TimeUnit timeUnit = TimeUnit.SECONDS;
        workerGroup.shutdownGracefully(quietPeriod, timeout, timeUnit);
        bossGroup.shutdownGracefully(quietPeriod, timeout, timeUnit);
    }

    public EventLoopGroup getWorkerGroup() {
        return workerGroup;
    }

}
